﻿using System;
using System.Collections.Generic;
using System.Text;

namespace ReferenceSwap
{
    /// <summary>
    /// Basic methods that clean up syntax of checks
    /// </summary>
    public static class Guard
    {
        /// <summary>
        /// Throw an exception if the assertion is true
        /// </summary>
        /// <typeparam name="T">type of exception to throw</typeparam>
        /// <param name="assertion">check for true</param>
        /// <param name="message">message to put in exception</param>
        public static void Against<T>(bool assertion, string message) where T : Exception
        {
            if (assertion)
                throw (Exception)System.Activator.CreateInstance(typeof(T), new object[] { message });
        }
    }
    /// <summary>
    /// Simple Utility class
    /// </summary>
    public static class Util
    {
        /// <summary>
        /// Extension method for taking a collection of bytes to a hex string
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns>Hex string</returns>
        public static string BytesToHex(IEnumerable<byte> bytes)
        {
            if (bytes == null)
                return "";

            string hex = "";
            foreach (byte b in bytes)
                hex += string.Format("{0:X2}", b);
            return hex;
        }
    }

    /// <summary>
    /// Utility class for getting a readable name from camel casing
    /// </summary>
    public static class CamelCaseSplit
    {
        /// <summary>
        /// Split a Camel Case String to a readable name
        /// </summary>
        /// <param name="src">Camel Case String</param>
        /// <returns>readable name</returns>
        public static string SplitToName(string src)
        {
            return SplitToName(src, true);
        }

        /// <summary>
        /// Split a Camel Case String to a readable name
        /// </summary>
        /// <param name="src">Camel case string</param>
        /// <param name="handleAcronyms">treat multiple capital letters in a row as an acronym</param>
        /// <returns>readable name</returns>
        public static string SplitToName(string src, bool handleAcronyms)
        {
            string[] words = Split(src);

            if (!handleAcronyms)
            {
                return string.Join(" ", words);
            }

            StringBuilder name = new StringBuilder();
            name.Append(words[0]);

            for (int i = 1; i < words.Length; i++)
            {
                // only add a space before long words (i.e. not acronyms)
                // also check the previous word that should handle articles (i.e. HaveABall)
                if (words[i].Length > 1 || words[i - 1].Length != 1)
                {
                    name.Append(" ");
                }

                name.Append(words[i]);
            }

            return name.ToString();
        }

        /// <summary>
        /// Tokenize a string into an array of 'words' based on camel casing
        /// </summary>
        /// <param name="src">camel case string</param>
        /// <returns>array of tokens</returns>
        public static string[] Split(string src)
        {
            List<string> words = new List<string>();

            if (string.IsNullOrEmpty(src))
            {
                return words.ToArray();
            }

            int wordStart = 0;

            char[] letters = src.ToCharArray();

            for (int i = 1; i < letters.Length; i++)
            {
                if (char.IsUpper(letters[i]))
                {
                    words.Add(new string(letters, wordStart, i - wordStart));
                    wordStart = i;
                }
            }

            words.Add(new string(letters, wordStart, letters.Length - wordStart));
            return words.ToArray();
        }
    }
}
